package com.project.service.impl;


import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.common.core.page.PageDomain;
import com.common.core.page.TableDataInfo;
import com.common.utils.StringUtils;
import com.github.pagehelper.PageHelper;
import com.project.domain.bo.DmProjectTypeBo;
import com.project.domain.entity.DmBudgetStandardDate;
import com.project.domain.entity.DmProjectType;
import com.project.domain.entity.SyntProject;
import com.project.domain.vo.DmProjectTypeVo;
import com.project.mapper.BudgetStandardDateMapper;
import com.project.mapper.ProjectTypeMapper;
import com.project.service.IBudgetStandardDateService;
import com.project.service.IProjectTypeService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;


/**
 * 项目分类列Service业务层处理
 *
 * @author ruoyi
 * @date 2025-02-08
 */
@Service
public class ProjectTypeServiceImpl extends ServiceImpl<ProjectTypeMapper, DmProjectType> implements IProjectTypeService {
    @Autowired
    private ProjectTypeMapper baseMapper;

    @Autowired
    private BudgetStandardDateMapper standardDateMapper;

    @Autowired
    private IBudgetStandardDateService standardDateService;

    /**
     * 查询项目分类
     *
     * @param id 项目分类列主键
     * @return 项目分类列
     */
    @Override
    public DmProjectTypeVo selectDmProjectTypeByID(String id) {
        DmProjectType projectType = this.getById(id);
        DmProjectTypeVo projectTypeVo = new DmProjectTypeVo();
        BeanUtils.copyProperties(projectType, projectTypeVo);

        LambdaQueryWrapper<DmBudgetStandardDate> lqw = new LambdaQueryWrapper<>();
        lqw.eq(StringUtils.isNotEmpty(id), DmBudgetStandardDate::getProjectTypeId, id);
        List<DmBudgetStandardDate> BudgetStandardDateList = standardDateService.list(lqw);
        projectTypeVo.setBudgetStandardDateList(BudgetStandardDateList);
        return projectTypeVo;
    }

    /**
     * 查询项目分类列表
     *
     * @param
     * @return 项目分类列
     */
    @Override
    public List<DmProjectType> selectDmProjectTypeList(String code, String name, String projectLevelId, String classId) {
        LambdaQueryWrapper<DmProjectType> lqw = new LambdaQueryWrapper<>();
        lqw.like(StringUtils.isNotEmpty(code), DmProjectType::getCode, code);
        lqw.like(StringUtils.isNotEmpty(name), DmProjectType::getName, name);
        lqw.eq(StringUtils.isNotEmpty(classId), DmProjectType::getClassId, classId);
        lqw.eq(StringUtils.isNotEmpty(projectLevelId), DmProjectType::getProjectLevelId, projectLevelId);
        lqw.orderBy(true, true, DmProjectType::getCode);

        List<DmProjectType> dmProjectTypes = baseMapper.selectDmProjectTypeList(lqw);
        return dmProjectTypes;
    }


    @Override
    public TableDataInfo selectDmProjectTypeList_haveCount(String code, String name, String projectLevelId, String classId, PageDomain page) {
        // 1：查询所有数据，不分页
        LambdaQueryWrapper<DmProjectType> lqw = new LambdaQueryWrapper<>();
        lqw.like(StringUtils.isNotEmpty(code), DmProjectType::getCode, code);
        lqw.like(StringUtils.isNotEmpty(name), DmProjectType::getName, name);
        lqw.eq(StringUtils.isNotEmpty(classId), DmProjectType::getClassId, classId);
        lqw.eq(StringUtils.isNotEmpty(projectLevelId), DmProjectType::getProjectLevelId, projectLevelId);
        lqw.orderBy(true, true, DmProjectType::getCode);
        List<DmProjectTypeVo> dmProjectTypes = baseMapper.selectDmProjectTypeList_haveCount(lqw);
        //因为需要统计数量,sql没有分页,所以不使用select标签进行二次查询
        // 1.2 获取所有 id
        List<String> ids = dmProjectTypes.stream()
                .map(DmProjectType::getId)
                .collect(Collectors.toList());

        List<DmBudgetStandardDate> allDates=null;
        if (ids !=null && ids.size() !=0){
            // 1.3 查询所有子表记录
            allDates = standardDateMapper.selectAllBudgetStandardDates(ids);

            // 1.4 分组后挂到主表对象上
            Map<String, List<DmBudgetStandardDate>> grouped = allDates.stream()
                    .collect(Collectors.groupingBy(DmBudgetStandardDate::getProjectTypeId));

            for (DmProjectTypeVo type : dmProjectTypes) {
                type.setBudgetStandardDateList(grouped.getOrDefault(type.getId(), new ArrayList<>()));
            }
        }
        // 2：递归计算每个节点的 totalProjectCount
        buildRecursiveTotalCount(dmProjectTypes);

        // 3：手动分页，只返回当前页的数据
        Integer pageNum = page.getPageNum();
        Integer pageSize = page.getPageSize();
        int fromIndex = (pageNum - 1) * pageSize;
        int toIndex = Math.min(fromIndex + pageSize, dmProjectTypes.size());
        dmProjectTypes.subList(fromIndex, toIndex);

        List<DmProjectTypeVo> pagedList = fromIndex >= dmProjectTypes.size()
                ? Collections.emptyList()
                : dmProjectTypes.subList(fromIndex, toIndex);

      return   TableDataInfo.build(pagedList,dmProjectTypes.size());
    }

    /**
     * 构建每条记录被引用的数量(联动)
     * @param list
     */
    public void buildRecursiveTotalCount(List<DmProjectTypeVo> list) {
        // 1. 构建 CODE -> 对象 的映射
        Map<String, DmProjectType> codeMap = list.stream()
                .collect(Collectors.toMap(DmProjectType::getCode, Function.identity()));

        // 2. 初始化每个节点的总数为它自己的项目数量
        for (DmProjectTypeVo stat : list) {
            stat.setTotalProjectCount(stat.getProjectCount());
        }

        // 3. 遍历每个节点，从下往上累加到祖先
        for (DmProjectTypeVo stat : list) {
            int projectCount = stat.getProjectCount();
            String parentCode = stat.getUpCode();

            // 向所有祖先节点逐级累加
            while (parentCode != null && codeMap.containsKey(parentCode)) {
                DmProjectType parent = codeMap.get(parentCode);
                parent.setTotalProjectCount(parent.getTotalProjectCount() + projectCount);
                parentCode = parent.getUpCode(); // 继续向上走
            }
        }
    }


    /**
     * 新增项目分类
     *
     * @param dmProjectType 项目分类列
     * @return 结果 100 -> 分类编号已存在
     * 200  -> 新增加成功
     * 500  -> 新增失败
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public int insertDmProjectType(DmProjectTypeBo dmProjectType) {
        DmProjectType projectType = dmProjectType.getProjectType();
        //分类编号
        String code = projectType.getCode();
        LambdaQueryWrapper<DmProjectType> lqw = new LambdaQueryWrapper<>();
        lqw.eq(DmProjectType::getCode, code);
        //科目前缀的数量
        Long prefixNum = baseMapper.selectCount(lqw);
        if (prefixNum != 0L) return 100;


        String parentId = projectType.getParentId();
        List<DmBudgetStandardDate> budgetStandardDateList = dmProjectType.getBudgetStandardDateList();
        //设置belongType
        String belongType = this.ReverseQueryProjectType(projectType.getUpCode());
        projectType.setBelongType(belongType + projectType.getName());
        //默认为0
        projectType.setHasChildren(0);
        boolean saveProjectType = this.save(projectType);
        //如果父级id不为空,代表新增的是子分类,需要将父级的hasChildren修改为1
        if (StringUtils.isNotEmpty(parentId)) this.updateParentState(parentId, 1);

        if (saveProjectType && budgetStandardDateList != null && !budgetStandardDateList.isEmpty()) {
            budgetStandardDateList.forEach(e -> {
                e.setProjectTypeId(projectType.getId());
            });
            boolean saveBatch = standardDateService.saveBatch(budgetStandardDateList);
            return saveBatch ? 200 : 500;
        }

        return saveProjectType ? 200 : 500;
    }

    /**
     * 修改父级分类的状态
     *
     * @param parentId 父级id
     * @param updateTo 修改到多少
     * @return
     */
    public Boolean updateParentState(String parentId, int updateTo) {
        DmProjectType ProjectType = this.getById(parentId);
        int hasChildren = ProjectType.getHasChildren();
        //如果已经是目标状态,直接返回
        if (hasChildren == updateTo) return true;
        LambdaUpdateWrapper<DmProjectType> luw = new LambdaUpdateWrapper<>();
        luw.set(DmProjectType::getHasChildren, updateTo);
        luw.eq(DmProjectType::getId, parentId);
        boolean update = this.update(luw);
        return update;
    }


    /**
     * 修改项目分类
     *
     * @param dmProjectType 项目分类列
     * @return 结果
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean updateDmProjectType(DmProjectTypeBo dmProjectType) {
        DmProjectType projectType = dmProjectType.getProjectType();
        List<DmBudgetStandardDate> budgetStandardDateList = dmProjectType.getBudgetStandardDateList();

        //原来的分类
        LambdaQueryWrapper<DmProjectType> lqw=new LambdaQueryWrapper<>();
        lqw.eq(DmProjectType::getId,projectType.getId());
        DmProjectType oldProjectType  = this.getOne(lqw);

        //设置belongType
        String belongType = this.ReverseQueryProjectType(projectType.getUpCode());
        projectType.setBelongType(belongType + projectType.getName());
        Boolean updateBase = this.updateById(projectType);
        if (budgetStandardDateList.isEmpty()) return updateBase;
        budgetStandardDateList.forEach(e -> {
            e.setProjectTypeId(projectType.getId());
        });
        boolean updateBudgetStandardDate = standardDateService.saveOrUpdateBatch(budgetStandardDateList);

        if (!projectType.getName() .equals(oldProjectType.getName())){
            //修改子级belongType涉及到的name值修改为新值
            List<DmProjectType> allChildTypes = baseMapper.getAllChildTypes(projectType.getId());
            Integer typeLevel = projectType.getTypeLevel();
            for (DmProjectType type: allChildTypes) {
                //他自己 - 跳过
                if (projectType.getId().equals(type.getId())) continue;
                //修改的name在第几级
                String thisBelongType = type.getBelongType();
                String newBelongType = this.replaceAtIndex(thisBelongType, typeLevel - 1, projectType.getName());
                LambdaUpdateWrapper<DmProjectType> luw=new LambdaUpdateWrapper();
                luw.set(StringUtils.isNotEmpty(newBelongType),DmProjectType::getBelongType,newBelongType)
                        .eq(DmProjectType::getId,type.getId());

                this.update(luw);
            }
        }

        return updateBudgetStandardDate;
    }

    //在索引位置替换值
    public  String replaceAtIndex(String input, int index, String newValue) {
        if (input == null || input.isEmpty()) {
            return input;
        }

        String[] parts = input.split("-");
        if (index < 0 || index >= parts.length) {
            return input;
        }

        parts[index] = newValue;
        return String.join("-", parts);
    }

    /**
     * 删除项目分类列信息
     *
     * @param id 项目分类列主键
     * @return 结果
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean deleteDmProjectTypeByID(String id) {
        //1.删从表
        LambdaUpdateWrapper<DmBudgetStandardDate> luwSubject = new LambdaUpdateWrapper<>();
        luwSubject.eq(DmBudgetStandardDate::getProjectTypeId, id);
        boolean delBudgetStandardDate = standardDateService.remove(luwSubject);
        //2.删主表
        DmProjectType projectType = baseMapper.selectById(id);
        String parentId = projectType.getParentId();
        boolean delBase = baseMapper.deleteById(id) > 0;
        //3.看是否需要将父级id的hasChildren改为0
        LambdaQueryWrapper<DmProjectType> lqw = new LambdaQueryWrapper<>();
        lqw.eq(DmProjectType::getParentId, parentId);
        //不是第一级
        if (StringUtils.isNotEmpty(parentId)) {
            long count = this.count(lqw);
            if (count == 0L) this.updateParentState(parentId, 0);
        }

        return delBudgetStandardDate && delBase;
    }

    @Override
    public String getMaxPrefix(String projectClass, String typeLevel, String upCode) {
        if ("xJProject".equals(projectClass) || "zXProject".equals(projectClass)) {//校级和纵向公用分类
            projectClass = "(class_id ='xJProject' or class_id ='zXProject')";
        } else {
            projectClass = "(class_id ='yfContract')";
        }
        String maxPrefix = baseMapper.getMaxPrefix(projectClass, typeLevel, upCode);
        if (maxPrefix == null) {
            return "";
        } else {
            return maxPrefix;
        }
    }

    @Override
    public List<SyntProject> getUseProjectList(String id,Integer pageNum,Integer pageSize) {
        List<String> allChildCodes = this.getAllChildCodes(id);

//        LambdaQueryWrapper<DmBudgetStandardDate> lqw=new LambdaQueryWrapper<>();
//        lqw.select(DmBudgetStandardDate::getBudgetStandardId)
//                .in(allChildCodes !=null && allChildCodes.size() >0,DmBudgetStandardDate::getProjectTypeId,allChildCodes);
//        List<String>  standardIds = standardDateService.listObjs(lqw, obj -> (String) obj);

        PageHelper.startPage(pageNum, pageSize);
        List<SyntProject> useProjectList = baseMapper.getUseProjectList(allChildCodes);
        PageHelper.clearPage(); // 防止影响其他查询
        return useProjectList;
    }

    /**
     * 根据分类id获取他的所有子节点的CODE(包含子节点的子节点)
     * @param id
     * @return
     */
    public List<String>   getAllChildCodes(String id) {
        return baseMapper.getAllChildCodes(id);
    }

    /**
     * 反着查询项目分类  从末级到最上级 获取完整的分类名 如:A_B_C
     *
     * @param upCode
     * @return
     */
    public String ReverseQueryProjectType(String upCode) {
        String belong_type = "";
        DmProjectType projectType = getProjectTypeByCode(upCode);
        while (projectType != null) {
            belong_type = projectType.getName() + "-" + belong_type;
            projectType = getProjectTypeByCode(projectType.getUpCode());
        }
        return StringUtils.isNotEmpty(belong_type)
                ? belong_type.substring(0, belong_type.length())
                : "";
    }

    private DmProjectType getProjectTypeByCode(String code) {
        if (StringUtils.isEmpty(code)) {
            return null;
        }
        LambdaQueryWrapper<DmProjectType> lqw = new LambdaQueryWrapper<>();
        lqw.eq(DmProjectType::getCode, code);
        return baseMapper.selectOne(lqw);
    }

}
